package com.ardf.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.ardf.common.EntityConstants;
import com.ardf.entity.*;
import com.ardf.entity.dto.*;
import com.ardf.entity.vo.DoPersonBatchVo;
import com.ardf.entity.vo.UpdateBatchVo;
import com.ardf.mapper.*;
import com.ardf.service.IBatchService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author ShiYunHao
 * @since 2025-01-06
 */
@Service
public class BatchServiceImpl extends ServiceImpl<BatchMapper, Batch> implements IBatchService {

    private final BatchMapper batchMapper;
    private final ProjectMapper projectMapper;
    private final AthleteProjectMapper athleteProjectMapper;
    private final SigninMapper signinMapper;
    private final AthleteTeamMapper athleteTeamMapper;
    private final AthleteMapper athleteMapper;


    public BatchServiceImpl(BatchMapper batchMapper, ProjectMapper projectMapper,
                            AthleteProjectMapper athleteProjectMapper, SigninMapper signinMapper,
                            AthleteTeamMapper athleteTeamMapper, AthleteMapper athleteMapper) {
        this.batchMapper = batchMapper;
        this.projectMapper = projectMapper;
        this.athleteProjectMapper = athleteProjectMapper;
        this.signinMapper = signinMapper;
        this.athleteTeamMapper = athleteTeamMapper;
        this.athleteMapper = athleteMapper;
    }

    @Override
    public List<BatchMenuDto> getMenu(Long competitionId) {
        List<Project> projectList = projectMapper.selectList(new LambdaQueryWrapper<Project>()
                .eq(Project::getCompetitionId, competitionId));
        List<BatchMenuDto> batchMenuDtos = projectList.stream().map(project -> {
            String projectName = getProjectNameByProjectId(project.getId());
            BatchMenuDto batchMenuDto = new BatchMenuDto();
            batchMenuDto.setProjectId(project.getId());
            batchMenuDto.setProjectName(projectName);
            batchMenuDto.setStartTime(project.getStartTime());
            batchMenuDto.setIsRelay(EntityConstants.PROJECT_CATEGORY_RELAY.equals(project.getCategory()));
            return batchMenuDto;
        }).collect(Collectors.toList());
        for (BatchMenuDto batchMenuDto : batchMenuDtos) {
            List<AthleteProject> athleteProjects = athleteProjectMapper.selectList(new LambdaQueryWrapper<AthleteProject>()
                    .eq(AthleteProject::getProjectId, batchMenuDto.getProjectId()));
            long signInCount = athleteProjects.stream().filter(athleteProject -> {
                Signin signin = signinMapper.selectOne(new LambdaQueryWrapper<Signin>()
                        .eq(Signin::getAthleteId, athleteProject.getAthleteId()));
                return "是".equals(signin.getStatus());
            }).count();
            if (signInCount == 0) {
                batchMenuDto.setIsFinished(true);
            } else {
                List<Batch> batches = batchMapper.selectList(new LambdaQueryWrapper<Batch>()
                        .eq(Batch::getProjectId, batchMenuDto.getProjectId()));
                batchMenuDto.setIsFinished(true);
                for (Batch batch : batches) {
                    if (batch.getSequence() == null) {
                        batchMenuDto.setIsFinished(false);
                        break;
                    }
                }
            }
        }
        batchMenuDtos.sort(Comparator.comparing(BatchMenuDto::getIsFinished));
        return batchMenuDtos;
    }

    @Override
    public Page<BatchTableRelayDto> searchAllRelay(Integer pageSize, Integer pageNum, Long projectId, String searchAll) {
        String projectName = getProjectNameByProjectId(projectId);
        Page<BatchTableRelayDto> page = new Page<>(pageNum, pageSize);
        Page<BatchTableRelayDto> result = batchMapper.searchAllRelay(page, projectId, searchAll);
        for (BatchTableRelayDto record : result.getRecords()) {
            record.setProjectName(projectName);
        }
        return result;
    }

    @Override
    public Page<BatchTablePersonDto> searchAllPerson(Integer pageSize, Integer pageNum, Long projectId, String searchAll) {
        String projectName = getProjectNameByProjectId(projectId);
        Page<BatchTablePersonDto> page = new Page<>(pageNum, pageSize);
        Page<BatchTablePersonDto> result = batchMapper.searchAllPerson(page, projectId, searchAll);
        for (BatchTablePersonDto record : result.getRecords()) {
            record.setProjectName(projectName);
        }
        return result;
    }

    /**
     * 通过id获得项目名
     */
    private String getProjectNameByProjectId(Long projectId) {
        Map<Byte, String> projectType = Map.of(EntityConstants.PROJECT_TYPE_FAST, "快速",
                EntityConstants.PROJECT_TYPE_MEDIUM, "中距离",
                EntityConstants.PROJECT_TYPE_SHORT, "短距离",
                EntityConstants.PROJECT_TYPE_SUNLIGHT, "阳光测向",
                EntityConstants.PROJECT_TYPE_STANDARD, "标准距离");
        Map<Byte, String> projectFrequency = Map.of(EntityConstants.PROJECT_FREQUENCY_2m, "2m",
                EntityConstants.PROJECT_FREQUENCY_80m, "80m");
        Map<Byte, String> projectCategory = Map.of(EntityConstants.PROJECT_CATEGORY_PERSON, "个人",
                EntityConstants.PROJECT_CATEGORY_RELAY, "接力");
        Project project = projectMapper.selectById(projectId);
        return projectType.get(project.getType()) + "-" + projectFrequency.get(project.getFrequency()) + "-" +
                projectCategory.get(project.getCategory());
    }

    @Override
    @Transactional
    public void doRandomPersonBatch(DoPersonBatchVo doPersonBatchVo) {
        //获取该项目
        Project project = projectMapper.selectById(doPersonBatchVo.getProjectId());
        int batchCount1=1;//第一批次
        int max_index=0;

        //获取当前项目的所有选手
        List<Athlete> athletes = batchMapper.getAthleteByProjectId(doPersonBatchVo.getProjectId());
        Map<Long,List<Long>> athleteMap = new HashMap<>();
        for (Athlete athlete : athletes){
            if(athleteMap.get(athlete.getGroupId())==null){
                athleteMap.put(athlete.getGroupId(),new ArrayList<>());
            }
            athleteMap.get(athlete.getGroupId()).add(athlete.getId());
        }
        //随机打乱各个组别的选手
        for(Long groupId:athleteMap.keySet()){
            Collections.shuffle(athleteMap.get(groupId),new Random(groupId/2));

            if(athleteMap.get(groupId).size()>max_index){
                max_index = athleteMap.get(groupId).size();
            }
        }

        for (int i = 0; i < max_index; i++) {
            //计算开始时间
            LocalTime localTime = doPersonBatchVo.getStartTime()
                    .plusSeconds(doPersonBatchVo.getInterval() * batchCount1);

            LocalDateTime batchTime = LocalDateTime.of(project.getStartTime().toLocalDate(), localTime);

            for (Long groupId : athleteMap.keySet()){
                if(i<athleteMap.get(groupId).size()){
                    //更新批次
                    batchMapper.update(new LambdaUpdateWrapper<Batch>()
                            .set(Batch::getSequence, batchCount1)
                            .set(Batch::getStartTime, batchTime)
                            .eq(Batch::getAthleteId, athleteMap.get(groupId).get(i))
                            .eq(Batch::getProjectId, doPersonBatchVo.getProjectId()));
                }
            }
            batchCount1++;
        }
    }


    @Override
    @Transactional
    public void doPersonBatch(DoPersonBatchVo doPersonBatchVo) {
        //获取该项目
        Project project = projectMapper.selectById(doPersonBatchVo.getProjectId());
        //参赛队总数
        int unitCount = batchMapper.getUnitCountByProjectId(doPersonBatchVo.getProjectId());
        List<UGAthleteCountDto> ugAthleteCountDtos = batchMapper.getUnitGroupAthleteCountListByProjectId(doPersonBatchVo.getProjectId());
        int maxAthleteCount = 0;
        for (UGAthleteCountDto ugAthleteCountDto : ugAthleteCountDtos) {
            if (ugAthleteCountDto.getAthleteCount() > maxAthleteCount) {
                maxAthleteCount = ugAthleteCountDto.getAthleteCount();
            }
        }
        //同场竞赛的不同组别数
        int groupCount = batchMapper.getGroupCountByProjectId(doPersonBatchVo.getProjectId());
        if (groupCount != 0) {
            //同队不同组别的间隔批次
            int intervalBatchCount = 0;
            if (unitCount % groupCount != 0) {
                intervalBatchCount = unitCount / groupCount + 1;
            } else {
                intervalBatchCount = unitCount / groupCount;
            }
            int totalBatchCount = unitCount * maxAthleteCount;
            if (totalBatchCount != 0) {
                List<Long> unitIds = batchMapper.getUnitIdListByProjectId(doPersonBatchVo.getProjectId());
                //抽签
                // 创建一个包含从1到N的列表
                List<Integer> randomSequence = new ArrayList<>();
                for (int i = 1; i <= unitCount; i++) {
                    randomSequence.add(i);
                }
                // 使用Collections.shuffle()方法随机打乱列表顺序
                Collections.shuffle(randomSequence);
                //抽签集合
                Map<Long, Integer> unitIdKeyMap = new HashMap<>();
                for (int i = 0; i < unitIds.size(); i++) {
                    unitIdKeyMap.put(unitIds.get(i), randomSequence.get(i));
                }
                System.out.println("sssssssssssssssssssss" + unitIdKeyMap);
                //按团队设置批次
                for (Long unitId : unitIdKeyMap.keySet()) {
                    //签号
                    Integer key = unitIdKeyMap.get(unitId);
                    //不同组之间的批次间隔
                    int interBatch = 0;
                    for (UGAthleteCountDto ugAthleteCountDto : ugAthleteCountDtos) {
                        if (unitId.equals(ugAthleteCountDto.getUnitId())) {
                            List<Long> athleteIds = batchMapper.
                                    getAthleteIdByGroupIdAndUnitId(ugAthleteCountDto.getGroupId(), unitId);
                            //同组之间的间隔
                            int sameGroupInterval = 0;
                            for (Long athleteId : athleteIds) {
                                //批次号
                                int batchCount = key + interBatch + sameGroupInterval;
                                if (batchCount > totalBatchCount) {
                                    batchCount -= totalBatchCount;
                                }
                                //获取该项目的开始时间
                                LocalTime localTime = doPersonBatchVo.getStartTime()
                                        .plusSeconds(doPersonBatchVo.getInterval() * batchCount);
                                LocalDateTime batchTime = LocalDateTime.of(project.getStartTime().toLocalDate(), localTime);
                                //更新批次
                                batchMapper.update(new LambdaUpdateWrapper<Batch>()
                                        .set(Batch::getSequence, batchCount)
                                        .set(Batch::getStartTime, batchTime)
                                        .eq(Batch::getAthleteId, athleteId)
                                        .eq(Batch::getProjectId, doPersonBatchVo.getProjectId()));
                                sameGroupInterval += unitCount;
                            }
                            interBatch += intervalBatchCount;
                        }
                    }
                }
            }
        }
        //公开组分批
        //获取公开组选手id
        List<Long> publicGroupAthleteIdList = batchMapper.getPublicGroupAthleteIdListByProjectId(doPersonBatchVo.getProjectId());
        System.out.println(publicGroupAthleteIdList.stream().toList());
        if (publicGroupAthleteIdList != null && !publicGroupAthleteIdList.isEmpty()) {
            System.out.println("pppppppppppppppppppppppppppppp");
            int batchCount1 = 1;
            for (Long athleteId : publicGroupAthleteIdList) {
                //获取该项目的开始时间
                LocalTime localTime = doPersonBatchVo.getStartTime()
                        .plusSeconds(doPersonBatchVo.getInterval() * batchCount1);
                LocalDateTime batchTime = LocalDateTime.of(project.getStartTime().toLocalDate(), localTime);
                System.out.println(athleteId+","+doPersonBatchVo.getProjectId());

                //更新批次
                batchMapper.update(new LambdaUpdateWrapper<Batch>()
                        .set(Batch::getSequence, batchCount1)
                        .set(Batch::getStartTime, batchTime)
                        .eq(Batch::getAthleteId, athleteId)
                        .eq(Batch::getProjectId, doPersonBatchVo.getProjectId()));
                batchCount1++;
            }
        }
    }

    @Override
    public void doRelayBatch(Long projectId) {
        List<TeamAthleteListDto> teamAthleteListDtos = batchMapper.getTeamAthleteListDtosByProjectId(projectId);
        for (TeamAthleteListDto teamAthleteListDto : teamAthleteListDtos) {
            int batchCount = 1;
            for (AthleteSubstituteDto athleteSubstituteDto : teamAthleteListDto.getAthleteSubstituteDtos()) {
                if (EntityConstants.ATHLETETEAM_SUBSTITUTE_NO.equals(athleteSubstituteDto.getSubstitute())) {
                    //不是替补
                    batchMapper.update(new LambdaUpdateWrapper<Batch>()
                            .set(Batch::getSequence, batchCount)
                            .eq(Batch::getAthleteId, athleteSubstituteDto.getAthleteId())
                            .eq(Batch::getProjectId, projectId));
                    batchCount++;
                } else {
                    //是替补
                    batchMapper.update(new LambdaUpdateWrapper<Batch>()
                            .set(Batch::getSequence, Integer.MAX_VALUE)//代表替补
                            .eq(Batch::getAthleteId, athleteSubstituteDto.getAthleteId())
                            .eq(Batch::getProjectId, projectId));
                }
            }
        }
    }

    @Override
    public List<CanExchangeDto> getExchange(Long batchId) {
        Batch batch = batchMapper.selectById(batchId);
        Project project = projectMapper.selectById(batch.getProjectId());
        if (EntityConstants.PROJECT_CATEGORY_RELAY.equals(project.getCategory())) {//接力
            AthleteTeam athleteTeam = athleteTeamMapper.selectOne(new LambdaQueryWrapper<AthleteTeam>()
                    .eq(AthleteTeam::getAthleteId, batch.getAthleteId()));
            return batchMapper.getCanExchangeRelayDtos(batch.getProjectId(), athleteTeam.getTeamId(), athleteTeam.getAthleteId());
        } else {//个人
            Athlete athlete = athleteMapper.selectById(batch.getAthleteId());
            return batchMapper.getCanExchangePersonDtos(batch.getProjectId(), batch.getAthleteId(),
                    athlete.getGroupId(), athlete.getUnitId());
        }
    }

    @Override
    @Transactional
    public void updateBatch(UpdateBatchVo updateBatchVo) {
        Batch fromBatch = batchMapper.selectById(updateBatchVo.getFromBatchId());
        Batch toBatch = batchMapper.selectById(updateBatchVo.getToBatchId());
        Batch batchTmp = new Batch();
        BeanUtils.copyProperties(fromBatch, batchTmp);
        fromBatch.setSequence(toBatch.getSequence());
        fromBatch.setStartTime(toBatch.getStartTime());
        toBatch.setSequence(batchTmp.getSequence());
        toBatch.setStartTime(batchTmp.getStartTime());
        batchMapper.updateById(fromBatch);
        batchMapper.updateById(toBatch);
    }

    @Override
    public void downloadBySequence(HttpServletResponse response, Long projectId) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("按批次号导出的批次表", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        List<DownloadBatchBySequenceDto> list = batchMapper.getAllBySequence(projectId);
        String projectName = getProjectNameByProjectId(projectId);
        for (DownloadBatchBySequenceDto downloadBatchBySequenceDto : list) {
            downloadBatchBySequenceDto.setProject(projectName);
            downloadBatchBySequenceDto.setRealStartTime(downloadBatchBySequenceDto.getStartTime().toLocalTime().toString());
        }
        EasyExcel.write(response.getOutputStream(), DownloadBatchBySequenceDto.class).sheet("表格1").doWrite(list);
    }

    @Override
    public void downloadByUnit(HttpServletResponse response, Long projectId) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("按单位导出的批次表", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        String projectName = getProjectNameByProjectId(projectId);
        Project project = projectMapper.selectById(projectId);
        List<Unit> units = batchMapper.getUnitByProjectId(projectId);
        if (EntityConstants.PROJECT_CATEGORY_RELAY.equals(project.getCategory())) {//接力
            // 方法2: 如果写到不同的sheet 同一个对象
            // 这里 指定文件
            try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), DownloadRelayBatchByUnitDto.class).build()) {
                if (units != null && !units.isEmpty()) {
                    int sheetNo = 0;
                    for (Unit unit : units) {
                        List<DownloadRelayBatchByUnitDto> list = batchMapper.getAllRelayByUnit(projectId, unit.getId());
                        for (DownloadRelayBatchByUnitDto downloadRelayBatchByUnitDto : list) {
                            downloadRelayBatchByUnitDto.setProject(projectName);
                            if (Integer.MAX_VALUE == downloadRelayBatchByUnitDto.getSequence()) {
                                downloadRelayBatchByUnitDto.setSequenceStr("替补");
                            } else {
                                downloadRelayBatchByUnitDto.setSequenceStr(String.valueOf(downloadRelayBatchByUnitDto.getSequence()));
                            }
                        }
                        // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样
                        WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo, unit.getName()).build();
                        excelWriter.write(list, writeSheet);
                        sheetNo++;
                    }
                } else {
                    WriteSheet writeSheet = EasyExcel.writerSheet(0, "空").build();
                    excelWriter.write(List.of(), writeSheet);
                }

            }
        } else {//个人
            try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), DownloadPersonBatchByUnitDto.class).build()) {
                if (units != null && !units.isEmpty()) {
                    int sheetNo = 0;
                    for (Unit unit : units) {
                        List<DownloadPersonBatchByUnitDto> list = batchMapper.getAllPersonByUnit(projectId, unit.getId());
                        for (DownloadPersonBatchByUnitDto downloadPersonBatchByUnitDto : list) {
                            downloadPersonBatchByUnitDto.setProject(projectName);
                            downloadPersonBatchByUnitDto.setRealStartTime(downloadPersonBatchByUnitDto.getStartTime().toLocalTime()
                                    .toString());
                        }
                        // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样
                        WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo, unit.getName()).build();
                        excelWriter.write(list, writeSheet);
                        sheetNo++;
                    }
                }else {
                    WriteSheet writeSheet = EasyExcel.writerSheet(0, "空").build();
                    excelWriter.write(List.of(), writeSheet);
                }
            }
        }
    }

    public Batch selectBatchByPIdAndAthId(Long projectId,Long athleteId){

        return batchMapper.selectOne(new LambdaQueryWrapper<Batch>().eq(Batch::getAthleteId,athleteId).eq(Batch::getProjectId,projectId));
    }
}
